using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.ObjectModel;
using System.Threading;

namespace PersistenceObject.Framework.Expressions
{
    public class Expression : IExpression
    {
        public static CustomExpression Create(String sql)
        {
            return new CustomExpression(sql);
        }

        public Expression()
        {
            this.expressions = new List<IExpression>();
            this.units = new List<string>();
            this.param = new Collection<FieldValue>();
        }

        public Expression(string name)
        {
            this.name = name;
        }

        private List<IExpression> expressions;
        public List<IExpression> Expressions
        {
            get { return expressions; }
            set { expressions = value; }
        }

        protected Collection<FieldValue> param;

        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        private object value;
        public object Value
        {
            get { return value; }
            set { this.value = value; }
        }

        private List<string> units;

        public void Add(params IExpression[] expressions)
        {
            this.Add(UniteType.And, expressions);
        }

        public void Add(UniteType unitetype, params IExpression[] expressions)
        {
            if (expressions != null)
            {
                for (int i = 0; i < expressions.Length; i++)
                {
                    IExpression expression = expressions[i];
                    if (expression != null)
                    {
                        this.units.Add(unitetype.ToString());
                        if (expression is Expression)
                        {
                            ((Expression)expression).ClearParams();
                        }
                        this.expressions.Add(expression);
                    }
                }
            }
        }

        public void ClearParams()
        {
            foreach (IExpression expression in this.expressions)
            {
                expression.ClearParams();
            }
            this.param.Clear();
        }

        public static Expression operator &(Expression exp1, Expression exp2)
        {
            Expression expression = new Expression();
            expression.Add(UniteType.And, new IExpression[] { exp1, exp2 });
            return expression;
        }

        public static Expression operator |(Expression exp1, Expression exp2)
        {
            Expression expression = new Expression();
            expression.Add(UniteType.Or, new IExpression[] { exp1, exp2 });
            return expression;
        }

        protected string GetSubString(IDbDriver dbOperator)
        {
            if (this.units.Count == 0)
            {
                return "";
            }
            StringBuilder sb = new StringBuilder();
            sb.Append("(");
            for (int i = 0; i < this.units.Count; i++)
            {
                if (i == 0)
                {
                    sb.Append(string.Concat(new object[] { " ", ((IExpression)this.expressions[i]).GetFilter(dbOperator), " " }));
                }
                else
                {
                    sb.Append(string.Concat(new object[] { " ", this.units[i], " ", ((IExpression)this.expressions[i]).GetFilter(dbOperator), " " }));
                }
            }
            sb.Append(")");
            return sb.ToString();
        }

        public virtual string GetFilter(IDbDriver dbOperator)
        {
            string filter = this.GetSubString(dbOperator);
            if (string.IsNullOrEmpty(filter))
            {
                return " 1=1 ";
            }
            return filter;
        }

        public virtual Collection<FieldValue> GetDataParams(IDbDriver dbOperator)
        {
            return this.GetSubParams(dbOperator);
        }

        protected Collection<FieldValue> GetSubParams(IDbDriver dbOperator)
        {
            if (this.expressions.Count == 0)
            {
                return null;
            }
            if (this.expressions.Count == 1)
            {
                return ((IExpression)this.expressions[0]).GetDataParams(dbOperator);
            }
            Collection<FieldValue> collection, subCollection;
            collection = new Collection<FieldValue>();
            foreach (IExpression exp in this.expressions)
            {
                subCollection = exp.GetDataParams(dbOperator);
                if ((subCollection != null) && (subCollection.Count > 0))
                {
                    foreach (FieldValue var in subCollection)
                    {
                        collection.Add(var);
                    }
                    subCollection.Clear();
                }
            }
            return collection;
        }

        protected int GetParamCount()
        {
            int i = 0;
            LocalDataStoreSlot slot = Thread.GetNamedDataSlot("PersistenceObject By Songchuan");
            object value = Thread.GetData(slot);
            if (value != null)
            {
                i = (int)value;
            }
            i++;
            Thread.SetData(slot, i);
            return i;
        }

        internal static void DoClear()
        {
            LocalDataStoreSlot slot = Thread.GetNamedDataSlot("PersistenceObject By Songchuan");
            if (Thread.GetData(slot) != null)
            {
                Thread.SetData(slot, null);
            }
        }

        #region Only for SqlServer2005 ServiceBroker
        public virtual string ServiceBrokerGetFilter(IDbDriver dbOperator)
        {
            string filter = this.ServiceBrokerGetSubString(dbOperator);
            if (string.IsNullOrEmpty(filter))
            {
                return " 1=1 ";
            }
            return filter;
        }

        protected string ServiceBrokerGetSubString(IDbDriver dbOperator)
        {
            if (this.units.Count == 0)
            {
                return "";
            }
            StringBuilder sb = new StringBuilder();
            sb.Append("(");
            for (int i = 0; i < this.units.Count; i++)
            {
                if (i == 0)
                {
                    sb.Append(string.Concat(new object[] { " ", ((IExpression)this.expressions[i]).ServiceBrokerGetFilter(dbOperator), " " }));
                }
                else
                {
                    sb.Append(string.Concat(new object[] { " ", this.units[i], " ", ((IExpression)this.expressions[i]).ServiceBrokerGetFilter(dbOperator), " " }));
                }
            }
            sb.Append(")");
            return sb.ToString();
        }
        #endregion
    }
}
